package api

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"shop/internal/models"
	"shop/internal/models/dto"
	"shop/internal/service/sys_config_service"
	"shop/internal/service/weixinuser_service"
	"shop/pkg/app"
	"shop/pkg/constant"
	"shop/pkg/global"
	"shop/pkg/jwt"
	"strings"
	"time"

	"gitee.com/phper95/pkg/cache"
	"github.com/gin-gonic/gin"
)

type LoginController struct{}

type wxConfig struct {
	AppID     string `json:"app_id"`
	AppSecret string `json:"app_secret"`
	// Appv2     string `json:"appv2"`
	// Appv3     string `json:"appv3"`
}

// LoginResponse 登录响应结构
type LoginResponse struct {
	Token  string           `json:"token"`
	User   *models.ShopUser `json:"user"`
	Expire int64            `json:"expire"`
	OpenID string           `json:"openid,omitempty"`
}

func (e *LoginController) WeixinLogin(c *gin.Context) {
	var (
		appG = app.Gin{C: c}
		req  dto.WeixinLoginRequest
	)

	// 绑定和验证参数
	httpCode, errCode := app.BindAndValid(c, &req)
	if errCode != constant.SUCCESS {
		appG.Response(httpCode, errCode, nil)
		return
	}

	// 获取微信配置
	wxConfig, err := e.getWechatConfig()
	if err != nil {
		appG.Response(http.StatusInternalServerError, constant.ERROR, err.Error())
		return
	}

	// 调用微信接口获取openid
	authResp, err := e.code2Session(wxConfig.AppID, wxConfig.AppSecret, req.Code)
	if err != nil {
		appG.Response(http.StatusBadRequest, constant.ERROR, "微信登录失败: "+err.Error())
		return
	}

	// 查询或创建用户
	shopUser, err := e.getOrCreateWechatUser(authResp.OpenID, authResp.SessionKey, &req)
	if err != nil {
		appG.Response(http.StatusInternalServerError, constant.ERROR, "用户处理失败: "+err.Error())
		return
	}

	// 生成JWT Token
	token, err := jwt.GenerateAppToken(shopUser, time.Hour*24*100)
	if err != nil {
		appG.Response(http.StatusInternalServerError, constant.ERROR, "Token生成失败: "+err.Error())
		return
	}

	// 验证 Redis 存储
	var key = constant.AppRedisPrefixAuth + token
	val, err := cache.GetRedisClient(cache.DefaultRedisClient).GetStr(key)
	if err != nil {
		global.LOG.Error("Redis存储验证失败", "error", err, "key", key)
	} else {
		global.LOG.Info("Redis存储成功", "key", key, "data_length", len(val))
	}

	// 构建登录响应
	loginResponse := LoginResponse{
		Token:  token,
		User:   shopUser,
		Expire: time.Now().Add(time.Hour * 24 * 100).Unix(),
		OpenID: authResp.OpenID,
	}

	appG.Response(http.StatusOK, constant.SUCCESS, loginResponse)
}

// getWechatConfig 获取微信配置
func (e *LoginController) getWechatConfig() (*wxConfig, error) {
	wechatConfig := sys_config_service.SysConfig{
		Id: 1,
		//Name: "hms_wechat",
	}
	configResult := wechatConfig.Get()
	if configResult.Content == nil {
		return nil, fmt.Errorf("无法获取微信配置")
	}

	// 类型断言，将 Content 转换为 *models.SysConfig
	sysConfig, ok := configResult.Content.(*models.SysConfig)
	if !ok {
		return nil, fmt.Errorf("微信配置类型转换失败")
	}

	// 直接使用模型字段构建 wxConfig
	wxConfig := &wxConfig{
		AppID:     sysConfig.AppID,
		AppSecret: sysConfig.AppSecret,
		// 如果配置存储在 content 字段中，需要解析 JSON
		// 否则直接使用上面的字段
	}

	// 如果 AppID 和 AppSecret 在 content 字段中（JSON格式）
	// if sysConfig.Content != "" {
	// 	// 解析 content 字段中的 JSON 配置
	// 	if err := json.Unmarshal([]byte(sysConfig.Content), &wxConfig); err != nil {
	// 		return nil, fmt.Errorf("微信配置JSON解析失败: %w", err)
	// 	}
	// }

	// 检查微信配置是否完整
	if wxConfig.AppID == "" || wxConfig.AppSecret == "" {
		return nil, fmt.Errorf("微信配置不完整")
	}
	return wxConfig, nil
}

// code2Session 调用微信接口换取 session_key 和 openid
func (e *LoginController) code2Session(appID, appSecret, code string) (*dto.WeixinAuthResponse, error) {
	url := fmt.Sprintf("https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
		appID, appSecret, code)

	resp, err := http.Get(url)
	if err != nil {
		return nil, fmt.Errorf("调用微信接口失败: %w", err)
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("读取响应失败: %w", err)
	}

	var authResp dto.WeixinAuthResponse
	if err := json.Unmarshal(body, &authResp); err != nil {
		return nil, fmt.Errorf("解析响应失败: %w", err)
	}

	if authResp.ErrCode != 0 {
		return nil, fmt.Errorf("微信接口错误: %d - %s", authResp.ErrCode, authResp.ErrMsg)
	}

	if authResp.OpenID == "" {
		return nil, fmt.Errorf("获取openid失败")
	}

	return &authResp, nil
}

// // 查询或创建微信用户
func (e *LoginController) getOrCreateWechatUser(openID string, SessionKey string, req *dto.WeixinLoginRequest) (*models.ShopUser, error) {
	// 查询用户是否已经存在
	weixinUserService := weixinuser_service.User{OpenID: openID}
	userInfo := weixinUserService.GetOneUser()

	// 如果用户已存在，直接返回
	// if userInfo.Content != nil {
	// 	if shopUser, ok := userInfo.Content.(models.ShopUser); ok {
	// 		return &shopUser, nil
	// 	}
	// }

	// 如果用户已存在，更新sessionKey并返回
	if userInfo.Content != nil {
		if shopUser, ok := userInfo.Content.(models.ShopUser); ok {
			// 更新sessionKey
			if err := e.updateUserSessionKey(&shopUser, SessionKey); err != nil {
				return nil, err
			}
			return &shopUser, nil
		}
		return nil, fmt.Errorf("用户信息类型转换失败")
	}

	// 用户不存在，创建新用户
	return e.createNewWechatUser(openID, SessionKey, req)
}

// // 创建新的微信用户
func (e *LoginController) createNewWechatUser(openID string, SessionKey string, req *dto.WeixinLoginRequest) (*models.ShopUser, error) {
	// 生成默认用户名
	username := fmt.Sprintf("wx_%s", openID)
	if len(openID) > 8 {
		username = fmt.Sprintf("wx_%s", openID[:8])
	}

	// 创建新用户对象
	newUser := &models.ShopUser{
		OpenID:     openID, // 设置微信OpenID
		Username:   username,
		SessionKey: SessionKey,
		//Nickname: req.Nickname,
		//Avatar:   req.Avatar,
		//Gender:     req.Gender,
		//City:       req.City,
		//Province:   req.Province,
		//Country:    req.Country,
		SpreadUid:  req.SpreadUid,
		SpreadTime: time.Now(),
		UserType:   "wechat",
		LoginType:  "wechat",
		Status:     1, // 启用状态
		//CreateTime: time.Now(),
		//UpdateTime: time.Now(),
	}

	// 创建用户
	weixinUserService := weixinuser_service.User{
		OpenID: openID,
		M:      newUser,
	}

	err := weixinUserService.AddWeixinUser()
	if err != nil {
		return nil, fmt.Errorf("创建微信用户失败: %w", err)
	}

	// 重新查询创建的用户信息
	createdUserInfo := weixinUserService.GetOneUser()
	if createdUserInfo.Content == nil {
		return nil, fmt.Errorf("创建用户后查询用户信息失败")
	}

	// 类型断言获取用户对象
	if shopUser, ok := createdUserInfo.Content.(models.ShopUser); ok {
		return &shopUser, nil
	}

	return nil, fmt.Errorf("用户信息类型转换失败")
}

// updateUserSessionKey 更新用户sessionKey
func (e *LoginController) updateUserSessionKey(shopUser *models.ShopUser, sessionKey string) error {
	if shopUser.SessionKey == sessionKey {
		return nil // sessionKey未变化，无需更新
	}

	shopUser.SessionKey = sessionKey
	shopUser.UpdateTime = time.Now()

	weixinUserService := weixinuser_service.User{
		OpenID: shopUser.OpenID,
		M:      shopUser,
	}

	if err := weixinUserService.UpdateWeixinUser(); err != nil {
		return fmt.Errorf("更新用户sessionKey失败: %w", err)
	}

	return nil
}

// RefreshToken 刷新token接口
func (e *LoginController) RefreshToken(c *gin.Context) {
	var (
		appG = app.Gin{C: c}
	)

	// 从请求头获取token
	oldToken := c.GetHeader("Authorization")
	if oldToken == "" {
		appG.Response(http.StatusUnauthorized, constant.ERROR, "缺少认证信息")
		return
	}

	if strings.HasPrefix(oldToken, "Bearer ") {
		oldToken = strings.TrimPrefix(oldToken, "Bearer ")
	}

	// 直接验证token而不使用claims变量
	_, err := jwt.ValidateToken(oldToken)
	if err != nil {
		appG.Response(http.StatusUnauthorized, constant.ERROR, "无效的token: "+err.Error())
		return
	}

	// 获取用户详细信息
	shopUser, err := jwt.GetAppDetailUser(c)
	if err != nil {
		appG.Response(http.StatusUnauthorized, constant.ERROR, "获取用户信息失败: "+err.Error())
		return
	}

	// 检查用户是否存在
	if shopUser.Id == 0 {
		appG.Response(http.StatusUnauthorized, constant.ERROR, "用户不存在")
		return
	}

	// 使用 weixinuser_service 查询用户信息
	weixinUserService := weixinuser_service.User{Id: shopUser.Id}
	userResult := weixinUserService.GetUserInfo() // 实际执行查询
	if userResult.Content == nil {
		appG.Response(http.StatusNotFound, constant.ERROR, "用户不存在")
		return
	}

	// 类型断言获取最新的用户信息
	if latestUser, ok := userResult.Content.(*models.ShopUser); ok {
		shopUser = latestUser // 使用最新的用户信息
	} else {
		global.LOG.Warn("用户信息类型断言失败，使用旧用户信息", "user_id", shopUser.Id)
	}

	// 生成新的JWT Token
	newToken, err := jwt.GenerateAppToken(shopUser, time.Hour*24*100)
	if err != nil {
		appG.Response(http.StatusInternalServerError, constant.ERROR, "Token生成失败: "+err.Error())
		return
	}

	// 使旧token失效
	e.invalidateToken(oldToken, "refreshed")

	// 构建响应
	loginResponse := LoginResponse{
		Token:  newToken,
		User:   shopUser,
		Expire: time.Now().Add(time.Hour * 24 * 100).Unix(),
		OpenID: shopUser.OpenID,
	}

	appG.Response(http.StatusOK, constant.SUCCESS, loginResponse)
}

// Logout 用户退出登录
func (e *LoginController) Logout(c *gin.Context) {
	var (
		appG = app.Gin{C: c}
	)

	token := c.GetHeader("Authorization")
	if token != "" {
		if strings.HasPrefix(token, "Bearer ") {
			token = strings.TrimPrefix(token, "Bearer ")
		}

		// 使token失效
		e.invalidateToken(token, "logout")
	} else {
		global.LOG.Warn("Logout token is empty")
	}

	appG.Response(http.StatusOK, constant.SUCCESS, gin.H{
		"message": "退出登录成功",
	})
}

// invalidateToken 公用方法：使token失效
func (e *LoginController) invalidateToken(token string, reason string) {
	redisClient := cache.GetRedisClient(cache.DefaultRedisClient)
	if redisClient == nil {
		global.LOG.Error("Redis client is nil, cannot invalidate token")
		return
	}

	// 删除Redis中的token数据
	tokenKey := constant.AppRedisPrefixAuth + token
	err := redisClient.Delete(tokenKey)
	if err != nil {
		global.LOG.Error("Failed to delete token from Redis",
			"error", err,
			"key", tokenKey,
			"reason", reason)
	} else {
		global.LOG.Info("Token invalidated successfully",
			"key", tokenKey,
			"reason", reason,
			"token_prefix", token[:min(20, len(token))]+"...")
	}

	// 将token加入黑名单
	blacklistKey := "token_blacklist:" + token
	_ = redisClient.Set(blacklistKey, reason, 15*time.Minute)
}

// 辅助函数，避免切片越界
func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}
